package com.irain.pp.account.service.impl;

import com.irain.pp.account.service.dto.LoginInfo;
import com.irain.pp.account.repository.enums.VerifyCodeType;
import com.irain.pp.account.service.dto.VerifyCodeInfo;
import com.irain.pp.account.service.redis.PpUserRedisDao;
import com.irain.pp.account.repository.enums.AccountType;
import com.irain.pp.account.repository.model.PpUserDO;
import com.irain.pp.account.service.mgmt.PpUserManager;
import com.irain.pp.account.service.PpUserRegisterService;
import com.irain.pp.account.service.PpUserLoginService;
import com.irain.pp.tool.HashUtils;
import com.irain.pp.tool.ValidatorUtil;
import com.irain.pp.tool.BizAssert;
import com.irain.pp.tool.exception.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author WangYanPeng
 * @date 2017/11/2 11:17
 */
@Service
public class PpUserServiceImpl implements PpUserLoginService, PpUserRegisterService {

    private static long deviationTime = 20 * 1000;

    private static long loginVerifyExpire = 1296000;

    private static int verifyCodeLength = 4;

    private static int verifySignLength = 6;

    private static long verifyCodeExpire = 120;

    private static final HashUtils PASSWORD_HASH = HashUtils.V01;

    @Autowired
    private PpUserManager ppUserManager;
    @Autowired
    private PpUserRedisDao ppUserRedisDao;

    @Override
    public Long validateH5(String cookie, String ip, long expire) {
        long currentTime = System.currentTimeMillis();
        LoginInfo info = ppUserRedisDao.getH5Cookie(cookie);
        if (info == null) {
            return null;
        }
        long expireTime = info.getLoginTime() + loginVerifyExpire * 1000;
        if (currentTime > expireTime) {
            return null;
        }
        long calcTime = currentTime + expire * 1000;
        if (Math.abs(calcTime - expireTime) > deviationTime) {
            return null;
        }
        if (!info.getLoginIp().equals(ip)) {
            return null;
        }
        return info.getUserId();
    }

    @Override
    public String loginH5ByPassword(String loginName, String password, String ip) {
        AccountType accountType = AccountType.parseLoginName(loginName);
        BizAssert.isTrue(accountType.isAllowPasswordLogin(), "用户名与密码错误！");
        PpUserDO ppUserDO = ppUserManager.get(accountType, loginName);
        BizAssert.notNull(ppUserDO, "用户名与密码错误！");
        BizAssert.isTrue(HashUtils.validateWithVersion(password, ppUserDO.getPasswordHash()), "用户名与密码错误！");
        String cookie = HashUtils.COOKIE.createHash(ppUserDO.getUserName());
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setUserId(ppUserDO.getId());
        loginInfo.setLoginIp(ip);
        loginInfo.setLoginTime(System.currentTimeMillis());
        ppUserRedisDao.saveH5Cookie(cookie, loginInfo, loginVerifyExpire);
        return cookie;
    }

    @Override
    public PpUserDO registerByUserName(String userName, String password) {
        BizAssert.isTrue(ValidatorUtil.isUsername(userName), "用户名不符合要求！");
        PpUserDO oldUserDO = ppUserManager.get(AccountType.USER_NAME, userName);
        BizAssert.isNull(oldUserDO, "该用户名已经被使用！");
        String passwordHash = PASSWORD_HASH.createHash(password);
        return ppUserManager.create(AccountType.USER_NAME, userName, passwordHash);
    }

    @Override
    public String initRegisterByMobile(String mobile, String ip) {
        BizAssert.isTrue(ValidatorUtil.isMobile(mobile), "手机号格式不正确！");
        PpUserDO user = ppUserManager.get(AccountType.MOBILE, mobile);
        BizAssert.isNull(user, "该手机号已经被注册！");
        return sendVerifyCodeForMobile(VerifyCodeType.CREATE_USER_MOBILE, mobile, ip);
    }

    @Override
    public PpUserDO registerByMobile(String mobile, String verifyMark, String verifyCode) {
        validateMobileByVerifyCode(VerifyCodeType.CREATE_USER_MOBILE, mobile, verifyMark, verifyCode);
        PpUserDO ppUserDO = ppUserManager.get(AccountType.MOBILE, mobile);
        BizAssert.notNull(ppUserDO, "该手机号已经被注册！");
        return ppUserManager.create(AccountType.MOBILE, mobile, null);
    }

    private String sendVerifyCodeForMobile(VerifyCodeType codeType, String mobile, String ip) {
        BizAssert.isTrue(ValidatorUtil.isMobile(mobile), "手机号格式不正确！");
        VerifyCodeInfo currentCodeInfo = ppUserRedisDao.getVerifyCode(codeType, mobile);
        BizAssert.isNull(currentCodeInfo, "发送太频繁，请稍后再尝试！");
        String verifyCode = RandomUtils.genRandomNumber(verifyCodeLength);
        String verifyMark = RandomUtils.genRandomTextCaseInsensitive(verifySignLength);
        VerifyCodeInfo verifyCodeInfo = new VerifyCodeInfo();
        verifyCodeInfo.setCode(verifyCode);
        verifyCodeInfo.setMark(verifyMark);
        verifyCodeInfo.setIp(ip);
        ppUserRedisDao.saveVerifyCode(codeType, mobile, verifyCodeInfo, verifyCodeExpire);
        //todo send verifyCode to mobile by wyp;
        return verifyMark;
    }

    private void validateMobileByVerifyCode(VerifyCodeType codeType, String mobile, String verifyMark, String verifyCode) {
        BizAssert.isTrue(ValidatorUtil.isMobile(mobile), "手机号格式不正确！");
        VerifyCodeInfo verifyCodeInfo = ppUserRedisDao.getVerifyCode(codeType, mobile);
        BizAssert.notNull(verifyCodeInfo, "验证码已经失效，请重新发送！");
        BizAssert.isEqual(verifyCodeInfo.getMark(), verifyMark, "验证码已经失效，请重新发送！");
        BizAssert.isEqual(verifyCodeInfo.getCode(), verifyCode, "验证码不正确！");
    }

}
